package dingding

// 基于钉钉的Token颁发器
// 已经获取到authCode, 就认证authCode正确性, 并且查询用户身份信息
import (
	"context"
	"fmt"

	"gitee.com/go-course/go8/projects/devcloud/mcenter/apps/code"
	"gitee.com/go-course/go8/projects/devcloud/mcenter/apps/token"
	"gitee.com/go-course/go8/projects/devcloud/mcenter/apps/token/provider"
	"gitee.com/go-course/go8/projects/devcloud/mcenter/apps/user"
	"github.com/caarlos0/env/v6"
	"github.com/infraboard/mcube/app"
	"github.com/infraboard/mcube/exception"
	"github.com/infraboard/mcube/logger"
	"github.com/infraboard/mcube/logger/zap"
	"github.com/rs/xid"
)

// authCode换行用户身份
type issuer struct {
	user user.Service

	log logger.Logger
}

func (i *issuer) Init() error {
	i.user = app.GetInternalApp(user.AppName).(user.Service)
	i.log = zap.L().Named("issuer.dingding")
	return nil
}

func (i *issuer) GrantType() token.GRANT_TYPE {
	return token.GRANT_TYPE_DINGDING
}

// 需要authCode, 获取钉钉用户, 如果本地没有 这个用户， 还需要同步
func (i *issuer) IssueToken(ctx context.Context, req *token.IssueTokenRequest) (
	*token.Token, error) {
	// 加载测试配置(自己把配置放到配置文件里面)
	conf := NewDefaultDingDingConfig()
	if err := env.Parse(conf); err != nil {
		return nil, err
	}

	i.log.Debugf("auth code: %s", req.AuthCode)

	// 获取Token
	client := NewDingDingClient(conf)
	err := client.Login(ctx, req.AuthCode)
	if err != nil {
		return nil, err
	}

	// 获取用户信息
	du, err := client.GetUserInfo(ctx)
	if err != nil {
		return nil, err
	}

	// 认证通过, 确认用户是否存在
	descReq := user.NewDescriptUserRequestWithName(du.Username())
	lu, err := i.user.DescribeUser(ctx, descReq)
	if err != nil {
		if exception.IsNotFoundError(err) {
			// 进行用户的创建
			createReq := user.NewCreateUserRequest()
			createReq.Username = du.Username()
			createReq.Password = xid.New().String()
			createReq.Type = user.TYPE_SUB
			lu, err = i.user.CreateUser(ctx, createReq)
			if err != nil {
				return nil, err
			}
		} else {
			return nil, err
		}
	}

	// 如果用户在本地数据库存在, 需要更新信息
	fmt.Println(du)

	// LDAP认证检查通过, 颁发Token
	// 颁发Token
	tk := token.NewToken(req)
	tk.Domain = lu.Spec.Domain
	tk.Username = lu.Spec.Username
	tk.UserType = lu.Spec.Type
	tk.UserId = lu.Id

	return tk, nil
}

func (i *issuer) IssueCode(context.Context, *code.IssueCodeRequest) (*code.Code, error) {
	return nil, fmt.Errorf("not impl")
}

func init() {
	provider.Registe(&issuer{})
}
